<?php
/**
 * Created by PhpStorm.
 * User: jjj
 * Date: 2017/11/3
 * Time: 16:54
 */

namespace app\common\lib\pay;


use think\Env;
use think\Log;

class ApplePay implements IPay
{
    const BUNDLE_ID = 'hkgxkj.zhangqian.com';

    const MERCHANT_NAME = 'zhangqian';
    const MERCHANT_ID = 'merchant.zhangqian.com';

    const URL_VERIFY_RECEIPT_SANDBOX = 'https://sandbox.itunes.apple.com/verifyReceipt';
    const URL_VERIFY_RECEIPT = 'https://buy.itunes.apple.com/verifyReceipt';

    private static $instance = null;
    /**
     * @return static
     */
    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    /**
     * 下订单
     *
     * @param $out_trade_no string 订单号
     * @param $total_fee float 支付总金额
     * @param $body string 商品描述
     * @param $client_type integer 支付类型，比如 1-APP、2-微信页面，3-PC支付
     * @param $client_ip string 支付的客户端实际IP
     * @param $detail string
     * @param null|mixed $ext
     * @return mixed
     */
    function unifiedOrder($out_trade_no, $total_fee, $body, $client_type, $client_ip, $detail = '', $ext = null)
    {
        // TODO: Implement unifiedOrder() method.
        return null;
    }

    /**
     * 获取字段key，方便客户端调用
     *
     * @return string
     */
    function getKey()
    {
        // TODO: Implement getKey() method.
        return 'applepay';
    }


    public static function isSandboxServer() {
        return Env::get('applePay.isSandbox');
    }

    /**
     * 苹果支付验证 接口
     *
     * @param string $receipt 收到的数据
     * @return ApplePayResult
     */
    public function verifyReceipt(string $receipt): ApplePayResult {

        $data = json_encode(['receipt-data' => $receipt],JSON_UNESCAPED_UNICODE);

        $resp = $this->request(self::URL_VERIFY_RECEIPT, $data);
        $result = new ApplePayResult();
        if (self::APPLE_SUCCESS == $resp->status) {
            $result->isSandbox = false;
        } elseif (self::APPLE_ERROR_RECEIPT_IS_SANDBOX === $resp->status) {
            $resp = $this->request(self::URL_VERIFY_RECEIPT_SANDBOX, $data);
            $result->isSandbox = true;
        }

        if ($resp->status) {
            // 失败
            $result->success = false;
            $result->errorMessage = self::APPLE_ERROR_STATUS_MAP[$resp->status] ?? '';
        } else {
            if (self::BUNDLE_ID != $resp->receipt->bundle_id) {
                $result->success = false;
                $result->errorMessage = '商户id不正确';
            } else {
                // 成功
                $result->success = true;
                $result->productId = '';
            }
        }

        return $result;
    }

    public function checkValidReceipt(string $receipt) {
        $data = json_encode(['receipt-data' => $receipt],JSON_UNESCAPED_UNICODE);
        $resp = $this->request(self::URL_VERIFY_RECEIPT, $data);
        $result = new ApplePayResult();
        $result->success = true;
        $result->errorMessage = self::APPLE_ERROR_STATUS_MAP[$resp->status];
        return $result;
    }

    /**
     * @param $url
     * @param $data
     * @return mixed
     * @throws \HttpException
     */
    private function request($url, $data) {

        $ch = curl_init($url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

        curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);  //这两行一定要加，不加会报SSL 错误
        curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);


        $response = curl_exec($ch);
        $errno    = curl_errno($ch);
        $errmsg   = curl_error($ch);
        curl_close($ch);

        if ($errno) {
            throw new \HttpException($errmsg, $errno);
        }

        $data = json_decode($response);
        return $data;
    }

    const APPLE_SUCCESS = 0;
    const APPLE_ERROR_JSON_FORMAT = 21000;
    const APPLE_ERROR_RECEIPT_DATA = 21002;
    const APPLE_ERROR_RECEIPT_INVALID = 21003;
    const APPLE_ERROR_SHARED_SECRET = 21004;
    const APPLE_ERROR_RECEIPT_SERVER = 21005;
    const APPLE_ERROR_RECEIPT_EXPIRED = 21006;
    const APPLE_ERROR_RECEIPT_IS_SANDBOX = 21007;
    const APPLE_ERROR_RECEIPT_IS_PRODUCTION = 21008;
    const APPLE_ERROR_STATUS_MAP = [
        self::APPLE_ERROR_JSON_FORMAT           => 'App Store 不能读取你提供的JSON对象',
        self::APPLE_ERROR_RECEIPT_DATA          => 'receipt-data 域的数据有问题',
        self::APPLE_ERROR_RECEIPT_INVALID       => 'receipt 无法通过验证',
        self::APPLE_ERROR_SHARED_SECRET         => '提供的 shared secret 不匹配你账号中的 shared secret',
        self::APPLE_ERROR_RECEIPT_SERVER        => 'receipt 服务器当前不可用',
        self::APPLE_ERROR_RECEIPT_EXPIRED       => 'receipt 合法，但是订阅已过期。服务器接收到这个状态码时，receipt数据仍然会解码并一起发送',
        self::APPLE_ERROR_RECEIPT_IS_SANDBOX    => 'receipt是Sandbox receipt，但却发送至生产系统的验证服务',
        self::APPLE_ERROR_RECEIPT_IS_PRODUCTION => 'receipt是生产receipt，但却发送至Sandbox环境的验证服务',
    ];
}

/**
 * Class ApplePayResult
 * @package app\common\lib\pay
 *
 * @property bool success
 * @property bool isSandbox
 * @property string errorMessage
 * @property string productId
 */
class ApplePayResult {
    public $success;
    public $isSandbox;
    public $errorMessage;
    public $productId;
}